#include "data_conversion.h"

#include <string.h>
#include <array>
#include <stdexcept>
#include <map>


BYTE_VECTOR string_to_byte_vector(const std::string& str) {
	return BYTE_VECTOR(str.begin(), str.end());
}



void hash_value_to_hex_string(const HASH_VALUE& vec, std::string &out_hex_str) {
    out_hex_str.clear(); // 清除输出字符串的内容
    for (size_t i = 0; i < vec.size(); ++i) {
        char hexBuffer[3];
        snprintf(hexBuffer, sizeof(hexBuffer), "%02X", vec.at(i));
        out_hex_str += hexBuffer;
    }
}

inline uint8_t hex_char_to_nibble(char c) {
	if (c >= '0' && c <= '9') {
		return c - '0';
	}
	else if (c >= 'A' && c <= 'F') {
		return 10 + (c - 'A');
	}
	else if (c >= 'a' && c <= 'f') {
		return 10 + (c - 'a');
	}
	else {
		throw std::invalid_argument("Invalid hex character");
	}
}

HASH_VALUE hex_string_to_hash_value(const char* hex_str) {
	HASH_VALUE result;
	const size_t expected_len = 64;

	// 检查输入字符串长度
	if (std::strlen(hex_str) != expected_len) {
		throw std::invalid_argument("Hex string must be 64 characters long");
	}

	// 遍历每两个字符并转换
	for (size_t i = 0; i < expected_len; i += 2) {
		uint8_t high = hex_char_to_nibble(hex_str[i]);
		uint8_t low = hex_char_to_nibble(hex_str[i + 1]);
		result[i / 2] = (high << 4) | low;
	}

	return result;
}



std::string base64_encode(const std::string str0) {
	static const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	std::string ret;
	int i = 0;
	int j = 0;
	unsigned char char_array_3[3];
	unsigned char char_array_4[4];

	for (auto& c : str0) {
		char_array_3[i++] = c;
		if (i == 3) {
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for (i = 0; i < 4; i++)
				ret += base64_chars[char_array_4[i]];
			i = 0;
		}
	}

	if (i) {
		for (j = i; j < 3; j++)
			char_array_3[j] = '\0';

		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
		char_array_4[3] = char_array_3[2] & 0x3f;

		for (j = 0; j < i + 1; j++)
			ret += base64_chars[char_array_4[j]];

		while (i++ < 3)
			ret += '=';
	}

	return ret;
}

std::string base64_decode(const std::string code0) {
	static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	std::array<int, 256> decode_table;
	std::fill(decode_table.begin(), decode_table.end(), -1);
	for (int i = 0; i < 64; i++)
		decode_table[static_cast<unsigned char>(base64_chars[i])] = i;
	decode_table['='] = 0; 
	decode_table[0] = 0; 
	int in_len = code0.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && (code0[in_] != '=')) {
		char_array_4[i++] = code0[in_]; in_++;
		if (i == 4) {
			for (i = 0; i < 4; i++)
				if (decode_table[char_array_4[i]] == -1)
					return "";

			char_array_3[0] = (decode_table[char_array_4[0]] << 2) + ((decode_table[char_array_4[1]] & 0x30) >> 4);
			char_array_3[1] = ((decode_table[char_array_4[1]] & 0xf) << 4) + ((decode_table[char_array_4[2]] & 0x3c) >> 2);
			char_array_3[2] = ((decode_table[char_array_4[2]] & 0x3) << 6) + decode_table[char_array_4[3]];

			for (i = 0; i < 3; i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i) {
		for (j = i; j < 4; j++)
			char_array_4[j] = 0;

		for (j = 0; j < 4; j++) {
			int t = decode_table[char_array_4[j]];
			if (t == -1)
				return "";
		}

		char_array_3[0] = (decode_table[char_array_4[0]] << 2) + ((decode_table[char_array_4[1]] & 0x30) >> 4);
		char_array_3[1] = ((decode_table[char_array_4[1]] & 0xf) << 4) + ((decode_table[char_array_4[2]] & 0x3c) >> 2);
		char_array_3[2] = ((decode_table[char_array_4[2]] & 0x3) << 6) + decode_table[char_array_4[3]];

		for (j = 0; j < i - 1; j++)
			ret += char_array_3[j];
	}

	return ret;
}